package com.bifang.core.gateway.controller;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.bifang.common.exception.AppException;
import com.bifang.common.helper.ApplicationContextHelper;
import com.bifang.common.vo.AppResponse;
import com.bifang.core.gateway.support.ApiContainer;
import com.bifang.core.gateway.support.ApiModel;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author lvxk
 * @date 2022-06-13
 * @description 统一网关
 */
@RestController
@RequestMapping(value = "/common")
public class CommonController {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    /** Api本地容器 */
    private final ApiContainer apiContainer;

    public static final String FUNCCODE = "funcCode";

    public CommonController(ApiContainer apiContainer) {
        this.apiContainer = apiContainer;
    }

    /** 统一网关调用方法 */
    @PostMapping(value = "/function")
    public AppResponse invoke(
            HttpServletRequest request, HttpServletResponse response, @RequestBody String body) {
        JSONObject bodyObj = JSONUtil.parseObj(body);
        String paramFucCode = request.getParameter(FUNCCODE);
        if (ObjectUtils.isEmpty(paramFucCode) && ObjectUtils.isEmpty(bodyObj.get(FUNCCODE))) {
            throw new AppException("请输入功能编号funcCode");
        }
        String funcCode =
                !ObjectUtils.isEmpty(paramFucCode)
                        ? paramFucCode
                        : bodyObj.get(FUNCCODE).toString();
        logger.info("功能code：" + funcCode + "调用");
        // 获取api方法
        ApiModel apiModel = apiContainer.get(funcCode);
        if (ObjectUtils.isEmpty(apiModel)) {
            throw new AppException("未查询到功能编号funcCode为" + funcCode + "的方法");
        }
        // 获得spring bean
        Object bean = ApplicationContextHelper.getBean(apiModel.getBeanName());
        List<Object> paramList = new ArrayList<>();
        Method apiModelMethod = apiModel.getMethod();
        Parameter[] parameters = apiModelMethod.getParameters();
        // 遍历方法参数并赋值到list
        for (Parameter parameter : parameters) {
            if (parameter.getType().isAssignableFrom(request.getClass())) {
                paramList.add(request);
            } else if (parameter.getType().isAssignableFrom(response.getClass())) {
                paramList.add(response);
            } else {
                paramList.add(JSONUtil.toBean(body, parameter.getType()));
            }
        }
        Object result = null;
        // 通过反射调用方法
        try {
            if (parameters.length == 1) {
                result = apiModelMethod.invoke(bean, paramList.get(0));
            } else if (parameters.length == 2) {
                result = apiModelMethod.invoke(bean, paramList.get(0), paramList.get(1));
            } else if (parameters.length == 3) {
                result =
                        apiModelMethod.invoke(
                                bean, paramList.get(0), paramList.get(1), paramList.get(2));
            }
        } catch (Exception ex) {
            // 捕获内部异常并抛出
            assert ex instanceof InvocationTargetException;
            throw new AppException(
                    ((InvocationTargetException) ex).getTargetException().getMessage());
        }
        if (apiModelMethod.getReturnType().equals(Void.TYPE)) {
            return AppResponse.success();
        } else {
            return AppResponse.successData(result);
        }
    }
}
